<?php

class User extends Tut_Model {

    public $id;
    public $name;
    public $username;
    public $email;
    public $user_group_id;
    public $code_confirm_email;
    public $code_change_password;
    public $expire_change_password;
    public $password;
    public $join_date;
    public $last_login;
    public $last_update;
    public $is_subscribe;
    public $is_actived;
    public $is_deleted;
    private $_aSort;
    private $_aSearch;
    private $_aRealSort;

    const LEVEL_ADMIN = 1;
    const LEVEL_MEMBER = 2;
    const PERIOD_TIME_CHANGE_PASSWORD = 8640;

    public function __construct($id = 0, $email = '', $password = '', $join_date = 0, $last_login = 0, $user_group_id = 0, $last_update = 0, $is_subscribe = 0, $is_atived = 0, $code_confirm_email = '', $code_confirm_password = '', $expire_change_password = 0) {

        parent::__construct();
        $this->_load();

        $this->id = $id;
        $this->user_group_id = $user_group_id;
        $this->email = $email;
        $this->password = $password;
        $this->join_date = $join_date;
        $this->last_login = $last_login;
        $this->last_update = $last_update;
        $this->_bIsNew = false;
        $this->is_subscribe = $is_subscribe;
        $this->is_actived = $is_atived;
        $this->code_confirm_email = $code_confirm_email;
        $this->code_change_password = $code_confirm_password;
        $this->expire_change_password = $expire_change_password;
    }

    public function login($aUser = array(), $aOtherParam = false) {
        $aParam = $aOtherParam;

        if (!$aParam) {
            $aParam = array(
                'email' => $aUser['email'],
                'password' => $this->encrypt->hash($aUser['password']),
                'user_group_id' => $aUser['user_group_id']
            );
        }

        $oUser = $this->db->where($aParam)->get('user');

        if ($oUser->num_rows() > 0) {
            $oUser = $oUser->row();
            $this->session->set_userdata($this->config->item('data_login'), $oUser);

            return true;
        }

        return false;
    }

    public function register($userReg) {
        if (empty($userReg) || !is_array($userReg)) {
            return false;
        }

        foreach (array('reemail', 'repassword', 'captcha') as $item) {
            unset($userReg[$item]);
        }

        $userReg['password'] = $this->encrypt->hash($userReg['password']);
        $userReg['code_confirm_email'] = uniqid('', true);
        $userReg['user_group_id'] = MEMBER;
        $userReg['last_update'] = time();
        $userReg['join_date'] = time();
        if ((bool) $this->db->insert('user', $userReg)) {
            return (object) array('iId' => $this->db->insert_id(),
                        'sCodeConfirmEmail' => $userReg['code_confirm_email']);
        }

        return false;
    }

    public function logout() {
        $this->session->unset_userdata($this->config->item('data_login'));
        return true;
    }

    public function getListAdmin($offset, $asearch = null) {
        $this->db->select('SQL_CALC_FOUND_ROWS u.id, u.name, u.username, u.join_date, u.is_actived as actived,
            u.is_subscribe as subscribe, u.email, ug.name as user_group', false)
                ->from('user u')
                ->join('user_group ug', 'u.user_group_id = ug.id', 'left')
                ->where('u.is_deleted', 0);

        $asearch = $this->prepare_search($asearch);

        foreach ($asearch as $key => $val) {
            if (trim($val) == '') {
                continue;
            }

            switch ($key) {
                case 'u.username':
                case 'u.name':
                case 'u.email':
                    $this->db->like($key, $val);
                    break;
                default :
                    $this->db->where($key, $val);
                    break;
            }
        }

        $iLimit = $this->session->userdata($this->config->item('ele_per_page'));

        if (!$iLimit) {
            $iLimit = $this->config->item('per_page_admin');
        }

        $this->db->limit($iLimit, ($offset - 1) * $iLimit);

        foreach ($this->_aSort as $key => $value) {
            $this->db->order_by($this->_aRealSort[$key], $value);
        }

        $oUser = $this->db->get();
        $aUser = array();

        if ($oUser->num_rows() > 0) {
            foreach ($oUser->result() as $user) {
                $user->join_date = date('Y-m-d', $user->join_date);
                $aUser[] = $user;
            }
        }

        $this->_itotal_rows = $this->db->query('SELECT FOUND_ROWS() AS count', false)->row()->count;

        return $aUser;
    }

    public function prepare_search($asearch = null) {
        if (empty($asearch)) {
            return array();
        }
        //Prepare search.
        $areturn = array(
            'u.name' => $asearch['name'],
            'u.is_actived' => $asearch['is_actived'],
            'u.username' => $asearch['username'],
            'u.user_group_id' => $asearch['user_group'],
            'u.join_date >=' => strtotime($asearch['join_date']['from']),
            'u.join_date <=' => strtotime($asearch['join_date']['to']),
            'u.email' => $asearch['email'],
            'u.id >=' => $asearch['id']['from'],
            'u.id <=' => $asearch['id']['to']
        );

        if ($areturn['u.is_actived'] == -1) {
            unset($areturn['u.is_actived']);
        }

        if ($areturn['u.user_group_id'] == -1) {
            unset($areturn['u.user_group_id']);
        }

        if (!$areturn['u.join_date >=']) {
            unset($areturn['u.join_date >=']);
        }

        if (!$areturn['u.join_date <=']) {
            unset($areturn['u.join_date <=']);
        }

        if (!$areturn['u.id >=']) {
            unset($areturn['u.id >=']);
        }

        if (!$areturn['u.id <=']) {
            unset($areturn['u.id <=']);
        }

        return $areturn;
    }

    public function save(array $asave) {
        if (empty($asave)) {
            return false;
        }

        $iid = $asave['id'];
        unset($asave['id']);

        if (empty($iid)) {
            $asave = $this->_prepare_save($asave);
            if ((bool) $this->db->insert('user', $asave)) {
                return $asave;
            }
            return false;
        }

        $asave = $this->_prepare_save($asave, true);
        if ((bool) $this->db->update('user', $asave, array('id' => $iid))) {
            return $asave;
        }
    }
    
    public function delete($aid) {
        if (empty($aid)) {
            return false;
        }
        
        $this->db->where_in('id', array_values($aid));
        $this->db->update('user', array('is_deleted' => 1));

        if ($this->db->affected_rows() > 0) {
            return true;
        }

        return false;
    }

    private function _prepare_save(array $asave = null, $isEdit = false) {
        if (empty($asave)) {
            return false;
        }

        //Unset id to empty.
        if (!$isEdit) {
            unset($asave['id']);
        }

        $asave['password'] = $this->encrypt->hash($asave['password']);
        //Unset current page.
        unset($asave['cur_page']);
        //Unset token...
        unset($asave[$this->config->item('csrf_token_name')]);
        //$asave['product_category_id'] = $asave['category'];
        unset($asave['password_match']);
        $asave['is_actived'] = $asave['status'];
        unset($asave['status']);
        $asave['user_group_id'] = $asave['user_group'];
        unset($asave['user_group']);
        $asave['join_date'] = time();
        $asave['last_update'] = time();
        return $asave;
    }

    public function get_rule($iid = false, $bis_check_password = false) {
        $sunique_id = empty($iid) ? '' : "-{$iid}";

        $arule = array(
            array(
                'field' => 'user[name]',
                'label' => $this->lang->line("pharse var='user.name'"),
                'rules' => 'trim|required|min_length[2]'
            ),
            array(
                'field' => 'user[username]',
                'label' => $this->lang->line("pharse var='user.username'"),
                'rules' => "trim|required|alpha_dash|min_length[2]|is_unique[user.username{$sunique_id}]"
            ),
            array(
                'field' => 'user[email]',
                'label' => $this->lang->line("pharse var='user.email'"),
                'rules' => "trim|required|valid_email|is_unique[user.email{$sunique_id}]"
            ),
            array(
                'field' => 'user[status]',
                'label' => $this->lang->line("pharse var='user.status'"),
                'rules' => 'trim|required|greater_than[-1]|less_than[3]'
            ),
            array(
                'field' => 'user[user_group]',
                'label' => $this->lang->line("pharse var='user.user_group'"),
                'rules' => 'trim|required|is_natural'
            )
        );

        if ($bis_check_password) {
            $arule_password = array(array(
                    'field' => 'user[password]',
                    'label' => $this->lang->line("pharse var='user.password'"),
                    'rules' => 'trim|required|alpha_dash|min_length[4]|max_length[30]'),
                array(
                    'field' => 'user[password_match]',
                    'label' => $this->lang->line("pharse var='user.password_match'"),
                    'rules' => 'trim|required|matches[user[password]]')
            );

            $arule = array_merge($arule, $arule_password);
        }

        return $arule;
    }

    public function get_validation_error() {
        $afield = array('name', 'username', 'email', 'password', 'password_match',
            'status', 'user_group');
        $avalidation_error = array();

        foreach ($afield as $field) {
            $avalidation_error = array_merge($avalidation_error, array("{$field}" => form_error("user[{$field}]")));
        }

        return $avalidation_error;
    }

    public function get() {
        
    }

    public function gets() {
        
    }

    public function update() {
        
    }

    public function edit() {
        
    }

    public function removeUser() {
        
    }

    public function getByCodeChangePassword($sCode = '') {
        if (empty($sCode)) {
            return false;
        }

        $rUser = $this->db->select('*')
                ->from('user')
                ->where(array('code_change_password' => $sCode))
                ->get();

        if ($rUser->num_rows() > 0) {
            $oUser = $rUser->row();
            $this->assign($oUser);

            return $oUser;
        }

        return false;
    }

    public function activeAccount($sKey) {
        if (empty($sKey)) {
            return ACTIVE_NOSUCCESS;
        }

        $oUser = $this->getByConfirmCode($sKey);

        if (empty($oUser)) {
            return ACTIVE_NOSUCCESS;
        }
        if ((bool) $this->is_actived) {
            return ACTIVED;
        }

        if ((bool) $this->db->update('user', array('is_actived' => ACTIVE), array('code_confirm_email' => $sKey))) {
            return ACTIVE_SUCCESS;
        }

        return ACTIVE_NOSUCCESS;
    }

    public function getByConfirmCode($sKey = '') {
        $sKey = trim($sKey);

        if (empty($sKey)) {
            return false;
        }

        $user = $this->db->select('*')
                ->from('user')
                ->where('code_confirm_email', $sKey)
                ->get();

        if ($user->num_rows() > 0) {
            $oUser = $user->row();
            $this->assign($oUser);

            return $oUser;
        }

        return false;
    }

    private function _load() {
        $this->load->library('encrypt');
        $this->load->helper('date');

        //Property of email object.
        $this->_aProp = array(
            "id",
            "name",
            "username",
            "email",
            "user_group_id",
            "code_confirm_email",
            "code_change_password",
            "expire_change_password",
            "password",
            "join_date",
            "last_login",
            "last_update",
            "is_subscribe",
            "is_actived",
            "is_deleted"
        );

        $this->_aSort = $this->getSort();
        $this->_aRealSort = array('name' => 'u.name', 'username' => 'u.username', 'email' => 'u.email',
            'status' => 'u.is_actived', 'join_date' => 'u.join_date', 'user_group' => 'u.user_group_id', 'id' => 'u.id');
    }

    public function getSort() {
        $this->_aSort = $this->session->userdata($this->config->item('sort'));

        if (!(bool) $this->_aSort) {
            return array('join_date' => 'desc');
        }

        return $this->_aSort;
    }

    public function sort($scol = '') {
        if (empty($scol)) {
            return false;
        }

        $stype_sort = $this->prepare_sort($scol);

        if (!$stype_sort) {
            $this->session->unset_userdata($this->config->item('sort'));
        } else {
            $this->session->set_userdata($this->config->item('sort'), $this->_aSort);
        }

        return $stype_sort;
    }

    public function prepare_sort($scol) {
        if (empty($scol)) {
            return false;
        }

        if (empty($this->_aSort[$scol])) {
            $this->_aSort = array($scol => 'desc');

            return 'desc';
        } else {
            $stype_sort = $this->_aSort[$scol] == 'desc' ? 'asc' : null;

            if (!$stype_sort) {
                unset($this->_aSort[$scol]);
            } else {
                $this->_aSort[$scol] = $stype_sort;
            }

            return $stype_sort;
        }

        return false;
    }

    public function setInfoChangePassword($sCode = '', $iTime = 0, $sEmail = '') {
        if (empty($sCode) || empty($iTime) || empty($sEmail)) {
            return false;
        }

        $this->db->update('user', array('code_change_password' => $sCode,
            'expire_change_password' => $iTime), array('email' => $sEmail));

        return true;
    }

    public function isExistedEmail($sEmail = null) {
        $sEmail = trim($sEmail);

        if (empty($sEmail)) {
            return false;
        }

        $oUser = $this->db->select('*')
                ->from('user')
                ->where(array(
                    'email' => $sEmail,
                    'user_group_id' => MEMBER))
                ->get();

        if ($oUser->num_rows() > 0) {
            return true;
        }

        return false;
    }

    public function isValidChangePassword($sCode = '', $iTime = 0) {
        if (empty($sCode) || empty($iTime)) {
            $this->_redirect_index();
        }

        $oUser = $this->db->select('*')
                ->from('user')
                ->where(array(
                    'code_change_password' => $sCode,
                    'expire_change_password' => $iTime,
                    'user_group_id' => MEMBER))
                ->get();

        if ($oUser->num_rows() > 0) {
            $oUser = $oUser->row();

            //Check time is still valid. in 1 days.
            $_iTime = $oUser->expire_change_password;
            if (time() - $_iTime > $this->getPeriodTimeChangePassword()) {
                $this->resetChangePassword($sCode, $iTime);

                return false;
            }

            return true;
        }

        return false;
    }

    public function resetChangePassword($sCode, $iTime) {
        if (empty($sCode) || empty($iTime)) {
            $this->_redirect_index();
        }

        $rResult = $this->db->update('user', array('code_change_password' => '',
            'expire_change_password' => null), array("code_change_password" => $sCode,
            'expire_change_password' => $iTime));

        if ((bool) $rResult) {
            return true;
        }

        return false;
    }

    public function getPeriodTimeChangePassword() {
        return 24 * 60 * 60;
    }

    public function changePassword($aPassword = null, $sCode = '', $iTime = 0) {
        if (empty($aPassword) || empty($sCode) || empty($iTime)) {
            return false;
        }

        $user = array(
            'password' => $this->encrypt->hash($aPassword['new_password']),
            "code_change_password" => '',
            "expire_change_password" => 0,
            "last_update" => time()
        );

        $this->getByCodeChangePassword($sCode);

        if ((bool) $this->db->update('user', $user, array('code_change_password' => $sCode,
                    'expire_change_password' => $iTime))) {

            $this->login(null, array(
                'email' => $this->email,
                'password' => $user['password'],
                'user_group_id' => $this->user_group_id
            ));

            return true;
        }

        return false;
    }

    public function get_by_id($iid = 0, $bis_check_active = true) {
        if (empty($iid)) {
            return false;
        }

        $this->db->select('u.id, u.name, u.username, u.join_date, u.is_actived as actived,
            u.is_subscribe as subscribe, u.email, u.user_group_id, u.password', false)
                ->from('user u')
                ->where('u.is_deleted', 0)
                ->where('u.id', $iid);

        if ($bis_check_active) {
            $this->db->where('u.is_actived', ACTIVE);
        }

        $oitem = $this->db->get();

        if ($oitem->num_rows() > 0) {
            $oitem = $oitem->row();
            $oitem->join_date = date('Y-m-d', $oitem->join_date);

            return $oitem;
        }

        return false;
    }

    public function isLogin() {
        if ((bool) $this->session->userdata($this->config->item('data_login'))) {
            return true;
        }

        return false;
    }

}

?>
